using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Collections;

namespace $safeprojectname$.Manager
{
    /// <summary>
    /// Cache Manager Singleton
    /// </summary>
    public class CacheManager
    {
        private static MemoryCache instance = null;

        /// <summary>
        /// Instance of memory cache
        /// </summary>
        public static MemoryCache Instance
        {
            get
            {
                if (instance == null)
                    instance = new MemoryCache();
                return instance;
            }
        }
    }

    /// <summary>
    /// Cache Manager
    /// </summary>
    public class MemoryCache : ICacheService
    {
        /// <summary>
        /// Expiration date of the object
        /// </summary>
        public DateTime NoAbsoluteExpiration
        {
            get { return DateTime.MaxValue; }
        }


        /// <summary>
        /// Retrieve the object in cache
        /// Is object doesn't exist in cache or is obsolete, getItemCallback method is called to fill the object
        /// </summary>
        /// <typeparam name="T">Object Type to put or get in cache</typeparam>
        /// <param name="httpContext">Http Context</param>
        /// <param name="cacheId">Object identifier in cache - Must be unique</param>
        /// <param name="getItemCallback">Callback method to fill the object</param>
        /// <param name="slidingExpiration">Expiration date</param>
        /// <returns>Object put in cache</returns>
        public T Get<T>(HttpContextBase httpContext, string cacheId, Func<T> getItemCallback, TimeSpan? slidingExpiration = null) where T : class
        {
            T item = HttpRuntime.Cache.Get(cacheId) as T;
            if (item == null)
            {
                item = getItemCallback();
                if (slidingExpiration == null)
                {
                    slidingExpiration = TimeSpan.FromSeconds(30);
                }
                httpContext.Cache.Insert(cacheId, item, null, NoAbsoluteExpiration, slidingExpiration.Value);
            }
            return item;
        }


        /// <summary>
        /// Retrieve the object in cache
        /// Is object doesn't exist in cache or is obsolete, getItemCallback method is called to fill the object
        /// </summary>
        /// <typeparam name="T">Object Type to put or get in cache</typeparam>
        /// <param name="httpContext">Http Context</param>
        /// <param name="cacheId">Object identifier in cache - Must be unique</param>
        /// <param name="getItemCallback">Callback method to fill the object</param>
        /// <param name="slidingExpiration">Expiration date</param>
        /// <returns>Object put in cache</returns>
        public T Retrieve<T>(HttpContextBase httpContext, string cacheId) where T : class
        {
            T item = HttpRuntime.Cache.Get(cacheId) as T;
            if (item == null)
            {
                return null;
            }
            return item;
        }

        /// <summary>
        /// Delete an oject using his unique id
        /// </summary>
        /// <param name="httpContext">Http Context</param>
        /// <param name="cacheId">Object identifier in cache</param>
        /// <returns></returns>
        public bool Clear(HttpContextBase httpContext, string cacheId)
        {
            var item = HttpRuntime.Cache.Get(cacheId);
            if (item != null)
            {
                httpContext.Cache.Remove(cacheId);
                return true;
            }
            return false;
        }

        /// <summary>
        /// Delete all object in cache
        /// </summary>
        /// <param name="httpContext">Http Context</param>
        public void ClearAll(HttpContextBase httpContext)
        {
            var item = HttpRuntime.Cache.GetEnumerator();
            while (item.MoveNext())
            {
                DictionaryEntry entry = (DictionaryEntry)item.Current;
                httpContext.Cache.Remove(entry.Key.ToString());
            }

        }
    }

    /// <summary>
    /// Cache manager interface
    /// </summary>
    interface ICacheService
    {
        /// <summary>
        /// Retrieve the object in cache
        /// Is object doesn't exist in cache or is obsolete, getItemCallback method is called to fill the object
        /// </summary>
        /// <typeparam name="T">Object Type to put or get in cache</typeparam>
        /// <param name="httpContext">Http Context</param>
        /// <param name="cacheID">Object identifier in cache - Must be unique</param>
        /// <param name="getItemCallback">Callback method to fill the object</param>
        /// <param name="slidingExpiration">Expiration date</param>
        /// <returns>Object put in cache</returns>
        T Get<T>(HttpContextBase httpContext, string cacheID, Func<T> getItemCallback, TimeSpan? slidingExpiration = null) where T : class;
    }

}
